﻿using MongoDB.Driver;
using Sustainalytics.Entities;
using Sustainalytics.Entities.Governance;
using Sustainalytics.ScreeningTool.Synchronization.Entities;
using System.Collections.Generic;
using System.Linq;

namespace Sustainalytics.ScreeningTool.Synchronization.Handlers.Governance
{
    public class GovernanceComputationResultHandler : IHandler<GovernanceComputationResult>
    {
        public ProjectionDefinition<GovernanceComputationResult> GetProjection(ProjectionDefinitionBuilder<GovernanceComputationResult> builder) => builder
            .Include(x => x.IssuesPerformance)
            .Include(x => x.OverallPerformance);

        public IEnumerable<ExtraElement> GetExtraElements(GovernanceComputationResult entity)
            => EnumerableExtensions.Concat(
                GetExtraElementsForOverallPerformance(entity.OverallPerformance),
                entity.IssuesPerformance?.SelectMany(GetExtraElementsForIssuePerformance));

        private static IEnumerable<ExtraElement> GetExtraElementsForOverallPerformance(GovernanceOverallPerformance overallPerformance)
        {
            if (overallPerformance == null)
                return new ExtraElementList();

            var regionPerformance = overallPerformance.GetRegionPerformance();

            return new ExtraElementList
            {
                { "Overall Corporate Governance Score-Score", overallPerformance.Score            },
                { "CG - Rank - Overall",                      regionPerformance?.GetPeerRanking() },
                { "CG - Percentile - Overall",                regionPerformance?.Percentile       },
            };
        }

        private static IEnumerable<ExtraElement> GetExtraElementsForIssuePerformance(GovernanceIssuePerformance issuePerformance)
        {
            var key = issuePerformance.Name;
            var regionPerformance = issuePerformance.GetRegionPerformance();

            return new ExtraElementList
            {
                { $"{key}-Score",             issuePerformance.Score              },
                { $"{key}-Weight",            issuePerformance.Weight             },
                { $"{key}-Weighted Score",    issuePerformance.WeightedScore      },
                { $"CG - Rank - {key}",       regionPerformance?.GetPeerRanking() },
                { $"CG - Percentile - {key}", regionPerformance?.Percentile       },
            };
        }
    }

    public static class GovernancePerformanceExtensions
    {
        public static GovernancePerformance GetRegionPerformance(this GovernanceIssuePerformance issuePerformance)
            => issuePerformance.Performances?.FirstOrDefault(x => x.PerformanceType == PerformanceType.Region);

        public static GovernancePerformance GetRegionPerformance(this GovernanceOverallPerformance overallPerformance)
            => overallPerformance.Performances?.FirstOrDefault(x => x.PerformanceType == PerformanceType.Region);

        public static PeerRanking GetPeerRanking(this GovernancePerformance performance)
            => new PeerRanking(performance.Rank, performance.GroupCount);
    }
}
